/**
 * 
 */
package exp.social.graph.dataaccess;

import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.query.Query;

import exp.social.graph.exceptions.CreateObjectException;
import exp.social.graph.exceptions.RemoveObjectException;
import exp.social.graph.model.Idable;
import exp.social.graph.model.ResourceModel;
import exp.social.graph.model.UserModel;

/**
 * @author Volodya Gavrysh
 * 
 */
public class ObjectDatabaseProvider implements DataProvider {

	public static final String DefaultDatabaseName = "database/tmp/experimental-social-graph.data";
	private String databaseName;

	public ObjectDatabaseProvider() {
	}

	public ObjectDatabaseProvider(String databaseName) {
		this.setDatabaseName(databaseName);
	}

	private static Integer getMax(ObjectContainer db, Idable idOb) {
		Query q = db.query();
		q.constrain(idOb.getClass());
		q.descend("id").orderDescending();
		ObjectSet result = q.execute();
		while (result.hasNext()) {
			Idable ob = (Idable) result.next();
			Integer ret = ob.getId();
			if (ret == null)
				ret = 0;
			return ret;
		}
		return 0;
	}

	@Override
	public DataProviderResult<UserModel> createUser(UserModel user) {
		ObjectContainer db = null;
		try {
			db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),
					getDatabaseName());
			if (user.getId() == null){
				Integer max = getMax(db, user);
				max++;
				user.setId(max);
			}
			ObjectSet<UserModel> users = db.queryByExample(user);
			if (users.hasNext()) {
				throw new CreateObjectException(
						"User with the specified id already exists");
			}
			db.store(user);
			return new DataProviderResult<UserModel>(user);
		} catch (Exception error) {
			return new DataProviderResult<UserModel>(null, false, error);
		} finally {
			if (db != null)
				db.close();
		}
	}

	@Override
	public DataProviderResult<ResourceModel> createResource(
			ResourceModel resource) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public DataProviderResult<UserModel> removeUser(UserModel user) {
		ObjectContainer db = null;
		try {
			db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),
					getDatabaseName());
			ObjectSet<UserModel> users = db.queryByExample(user);
			if (!users.hasNext()) {
				throw new RemoveObjectException(
						"No user with the specified id was found.");
			}
			db.delete(users.next());
			return new DataProviderResult<UserModel>(user);
		} catch (Exception error) {
			return new DataProviderResult<UserModel>(null, false, error);
		} finally {
			if (db != null)
				db.close();
		}
	}

	@Override
	public DataProviderResult<ResourceModel> removeResource(
			ResourceModel resource) {
		// TODO Auto-generated method stub
		return null;
	}

	public String getDatabaseName() {
		if (this.databaseName == null)
			return DefaultDatabaseName;
		return databaseName;
	}

	public void setDatabaseName(String databaseName) {
		this.databaseName = databaseName;
	}

	@Override
	public DataProviderResult<UserModel> getUserById(Integer userId) {
		ObjectContainer db = null;
		try {
			db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(),
					getDatabaseName());
			UserModel user = new UserModel();
			user.setId(userId);
			ObjectSet<UserModel> users = db.queryByExample(user);
			if (!users.hasNext()) {
				throw new RemoveObjectException(
						"No user with the specified id was found.");
			}
			return new DataProviderResult<UserModel>(users.next());
		} catch (Exception error) {
			return new DataProviderResult<UserModel>(null, false, error);
		} finally {
			if (db != null)
				db.close();
		}
	}

}
